﻿/// <summary>
/// Developer: CHOOI KAH WAI
/// Last Modified: 11/10/2009
/// </summary>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NyARToolkitCSUtils.Capture;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;


namespace ARSS.Components
{
    /// <summary>
    /// Camera component
    /// The implementation was refered to NyARToolkitCSUtils
    /// NyARToolkitCS(for C#) Copyright (C)2008 R.Iizuka
    /// NyARToolkitCS(for C#) can be obtained from http://nyatla.jp/nyartoolkit/wiki/index.php?NyARToolkitCS
    /// </summary>
    public class CamCom_NyAR : CamCom, CaptureListener
    {
        #region Variables

        /// <summary>
        /// Capture device list
        /// </summary>
        private CaptureDeviceList deviceList;

        /// <summary>
        /// Current selected capture device
        /// </summary>
        private CaptureDevice currentDevice;

        /// <summary>
        /// Video buffer
        /// </summary>
        private byte[] vidBuffer;

        #endregion

        #region Functions

        /// <summary>
        /// Constructor
        /// </summary>
        public CamCom_NyAR()
        {
            this.deviceList = new CaptureDeviceList();
            this.selectedIndex = -1;
        }

        #endregion

        #region CamCom Implementations 

        #region Delegates / Events

        public override event Coordinator.CameraUpdateHandler CameraUpdateEvent;

        #endregion

        #region Functions

        public override string[] GetCamNames()
        {
            string[] result = new string[this.deviceList.count];
            int i = 0;
            for (i = 0; i < this.deviceList.count; i++)
            {
                result[i] = this.deviceList[i].name;
            }
            return result;
        }

        public override void Init(int screenWidth, int screenHeight, int frameRate)
        {
            this.currentDevice.SetCaptureListener(this);
            this.currentDevice.PrepareCapture(screenWidth, screenHeight, frameRate);

            this.camVideoInfo = new CamVideoInfo();
            this.camVideoInfo.Bits = this.currentDevice.video_bit_count;
            this.camVideoInfo.Width = this.currentDevice.video_width;
            this.camVideoInfo.Height = this.currentDevice.video_height;
            this.camVideoInfo.Stride = this.camVideoInfo.Width * this.camVideoInfo.Bits / 8;
            this.camVideoInfo.VideoPixelFormat = PixelFormat.Format32bppRgb;

            this.vidBuffer = new byte[this.camVideoInfo.Height * this.camVideoInfo.Stride];
        }

        public override void StartCapture()
        {
            this.currentDevice.StartCapture();
        }

        public override void StopCapture()
        {
            CameraUpdateEvent = null;
            // Sometime the program will stop responding from here
            this.currentDevice.StopCapture();
        }

        public override void SetSelectedIndex(int selection)
        {
            this.selectedIndex = selection;
            this.currentDevice = this.deviceList[selection];
        }

        #endregion

        #endregion

        #region CaptureListener Implementations

        #region Functions

        /// <summary>
        /// On video buffer received
        /// </summary>
        /// <param name="_sender">Current capture device</param>
        /// <param name="_sampleTime">Sample time</param>
        /// <param name="_buffer">Video buffer</param>
        /// <param name="_bufferLen">Size of video buffer</param>
        public void OnBuffer(CaptureDevice sender, double sampleTime, IntPtr buffer, int bufferLen)
        {
            // Convert IntPtr to byte[]
            // Flip image vertically
            int w = this.camVideoInfo.Width * 4;
            int st = w * (this.camVideoInfo.Height - 1);
            int et = 0;
            for (int i = this.camVideoInfo.Height - 1; i >= 0; i--)
            {
                Marshal.Copy((IntPtr)((int)buffer + et), this.vidBuffer, st, w);
                st -= w;
                et += w;
            }

            if (CameraUpdateEvent != null)
                CameraUpdateEvent(this.vidBuffer);
          
        }

        #endregion

        #endregion
    }
}
